package com.yidao.core.service.impl;

import java.lang.reflect.ParameterizedType;
import java.sql.Timestamp;
import java.util.Calendar;
import java.util.List;

import javax.validation.Validator;

import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.criterion.DetachedCriteria;
import org.hibernate.criterion.Restrictions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.orm.hibernate3.HibernateTemplate;
import org.springframework.util.CollectionUtils;

import com.yidao.core.domain.BaseDomainObject;
import com.yidao.core.domain.SearchCriteria;
import com.yidao.core.domain.SearchExpression;
import com.yidao.core.domain.SearchOperator;
import com.yidao.core.service.BaseDomainObjectService;

public class BaseDomainObjectServiceImpl<T extends BaseDomainObject> extends BaseServiceImpl implements BaseDomainObjectService<T>{
	
	protected HibernateTemplate hibernateTemplate;
	
	
		
	protected void beforeCreate(T object){
	}
	
	@Override
	public void create(T object) {
		object.setStatus(BaseDomainObject.STATUS_ACTIVE);
		Calendar cal = Calendar.getInstance();
		cal.setTimeInMillis(System.currentTimeMillis());
		object.setCreateTime(cal);
		object.setUpdateTime(cal);
		beforeCreate(object);
		this.hibernateTemplate.save(object);
	}
	
	@Override
	public void delete(T object) {
		object.setStatus(BaseDomainObject.STATUS_DELETED);
		this.hibernateTemplate.update(object);
	}
	
	@Override
	public void deleteById(Long id) {
		T object = this.hibernateTemplate.get(this.getEntityClass(), id);
		this.delete(object);
	}
	
	@Override
	public T getById(Long id) {
		return hibernateTemplate.get(this.getEntityClass(), id);
	}
	
	public Class<T> getEntityClass(){
		return (Class<T>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0];
	}
	
	protected Session getSession(){
		return hibernateTemplate.getSessionFactory().getCurrentSession();
	}
	
	protected SessionFactory getSessionFactory(){
		return hibernateTemplate.getSessionFactory();
	}

	@Override
	public List<T> list(SearchCriteria criteria) {
		DetachedCriteria detachedCriteria = DetachedCriteria.forClass(this.getEntityClass());
		
		//set status to active.
		detachedCriteria.add(Restrictions.eq("status", BaseDomainObject.STATUS_ACTIVE));
		
		for(SearchExpression expression:criteria.getExpressions()){
			
			if(CollectionUtils.isEmpty(expression.getValues())){
				continue;
			}
			
			if(expression.getOperator() == SearchOperator.eq){
				if(expression.getValues().get(0) == null || StringUtils.isEmpty(expression.getValues().get(0).toString())){
					continue;
				}
				detachedCriteria.add(Restrictions.eq(expression.getPropertyName(),expression.getValues().get(0)));
			}else if(expression.getOperator() == SearchOperator.like){
				if(expression.getValues().get(0) == null || StringUtils.isEmpty(expression.getValues().get(0).toString())){
					continue;
				}
				detachedCriteria.add(Restrictions.like(expression.getPropertyName(),expression.getValues().get(0)));
			}else if(expression.getOperator() == SearchOperator.gt){
				if(expression.getValues().get(0) == null || StringUtils.isEmpty(expression.getValues().get(0).toString())){
					continue;
				}
				detachedCriteria.add(Restrictions.gt(expression.getPropertyName(),expression.getValues().get(0)));
			}else if(expression.getOperator() == SearchOperator.le){
				if(expression.getValues().get(0) == null || StringUtils.isEmpty(expression.getValues().get(0).toString())){
					continue;
				}
				detachedCriteria.add(Restrictions.le(expression.getPropertyName(),expression.getValues().get(0)));
			}else if(expression.getOperator() == SearchOperator.between){
				if(expression.getValues().get(0) == null || StringUtils.isEmpty(expression.getValues().get(0).toString())){
					continue;
				}
				if(expression.getValues().get(1) == null || StringUtils.isEmpty(expression.getValues().get(1).toString())){
					continue;
				}
				detachedCriteria.add(Restrictions.between(expression.getPropertyName(),expression.getValues().get(0),expression.getValues().get(1)));
			}else if(expression.getOperator() == SearchOperator.in){
				detachedCriteria.add(Restrictions.in(expression.getPropertyName(),expression.getValues()));
			}else{
				if(expression.getValues().get(0) == null || StringUtils.isEmpty(expression.getValues().get(0).toString())){
					continue;
				}
				detachedCriteria.add(Restrictions.eq(expression.getPropertyName(),expression.getValues().get(0)));
			}
		}
		return hibernateTemplate.findByCriteria(detachedCriteria);
	}

	@Override
	public List<T> listAll() {
		DetachedCriteria criteria = DetachedCriteria.forClass(this.getEntityClass());
		criteria.add(Restrictions.eq("status", BaseDomainObject.STATUS_ACTIVE));
		return hibernateTemplate.findByCriteria(criteria);
	}
	
	@Autowired
	public void setSessionFactory(SessionFactory sessionFactory) {
		this.hibernateTemplate = new HibernateTemplate(sessionFactory);
	}

	@Override
	public void update(T object) {
		Calendar cal = Calendar.getInstance();
		cal.setTimeInMillis(System.currentTimeMillis());
		object.setUpdateTime(cal);
		this.hibernateTemplate.update(object);
	}
}
